/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package db.xml;

import core.Book;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.transform.stream.StreamSource;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

/**
 * BookXML Class is used for retrieving Book objects via XML and HTTP
 * The class relies on XSD schema bookXmlSchema.xsd and bookListXmlSchema.xsd
 * to validate the XML source
 *
 * @author Peter
 */
public class BookXML {

    // schema locations for the xml validation
    private static final String BOOK_XSD = "schema/bookXmlSchema.xsd";
    private static final String BOOK_LIST_XSD = "schema/bookListXmlSchema.xsd";
    private String urlSource;
    // the querys/parameters to be used agains URL
    private static final String isbn10Parameter = "?isbn10=";
    private static final String isbn13Parameter = "?isbn13=";
    private static final String authorParameter = "?author=";
    private static final String titleParameter = "?title=";
    // this is due to the order of the book elements in the
    // book xml interface, the book parser relies on the
    // order of the elements!
    private static final int TITLE = 0;
    private static final int AUTHOR = 1;
    private static final int DESCRIPTION = 2;
    private static final int PRICE = 3;
    private static final int LINK = 4;
    private static final int ISBN10 = 5;
    private static final int ISBN13 = 6;
    // the entry point for the book should be "book"
    public static final String ROOT_ELEMENT_TAG = "book";

    /**
     * Constructor for the XML parsor class 
     * 
     * @param source (the URL for WS) ie. http://host.td/getBook.php
     */
    public BookXML(String source) {
        this.urlSource = source;
    }

    /**
     * Sets the URL source
     * @param source (the URL for WS) ie. http://host.td/getBook.php
     */
    public void setURL(String source) {
        this.urlSource = source;
    }

    /**
     * Gets a book by ISBN10
     * @param ISBN10
     * @return Book object or null if Query did not succeed
     */
    public Book getBookByISBN10(String ISBN10) {

        String url = urlSource + isbn10Parameter + ISBN10;
        return getBook(url);
    }

    /**
     * Gets a book by ISBN13
     * @param ISBN13
     * @return
     */
    public Book getBookByISBN13(String ISBN13) {
        String url = urlSource + isbn13Parameter + ISBN13;
        return getBook(url);
    }
    /**
     * Get a book by ISBN10 or ISBN13
     * Tries ISBN10 first, then ISBN13
     * @param ISBN10
     * @param ISBN13
     * @return
     */
        public Book getBookByISBN10AndISBN13(String ISBN10, String ISBN13) {
            Book book = getBookByISBN10(ISBN10);
            if (book!=null) return book;
            else return getBookByISBN13(ISBN13);
    }

    /**
     * Get a collection of books by author
     * @param author
     * @return
     */
    public Collection<Book> getBookByAuthor(String author) {
        String url = urlSource + authorParameter + author;
        return getBooks(url);
    }

    /**
     * gets a collecting of books by title
     * @param title
     * @return
     */
    public Collection<Book> getBookByTitle(String title) {
        String url = urlSource + titleParameter + title;
        return getBooks(url);
    }

    /**
     * private help method, gets a book by
     * @param xmlUrlString (i.e. http://shop.com/getBook?ISBN13=3233323332)
     * @return
     */
    private Book getBook(String xmlUrlString) {
        // validate book source
        URL xmlUrl;
        try {
            xmlUrl = new URL(xmlUrlString);
        } catch (MalformedURLException ex) {
            System.out.println(ex.getMessage());
            return null;
        }
        StreamSource bookXsd = new StreamSource(this.getClass().getResourceAsStream(BOOK_XSD));
        
        if (!XmlUtils.validateXML(bookXsd, xmlUrl)) {
            return null;
        }

        // book source should now be valid according do xsd!
        try {
            Document doc = getDocument(xmlUrlString);
            Element root = doc.getRootElement();
            return parseBook(root);

        } catch (JDOMException ex) {
            System.out.println(ex.getMessage());
        } catch (IOException ex) {
            System.out.println(ex.getMessage());
        }
        return null;
    }

    /**
     * get a collection of a book by URL
     * @param xmlUrlString (i.e. http://shop.com/getBook?title=hello)
     * @return
     */
    private Collection<Book> getBooks(String xmlUrlString) {
        List<Book> books = new ArrayList<Book>();

        // validate book source
        URL xmlUrl;
        try {
            xmlUrl = new URL(xmlUrlString);
        } catch (MalformedURLException ex) {
            System.out.println(ex.getMessage());
            return null;
        }
        StreamSource[] xsdFiles = {
            new StreamSource
                    (this.getClass().getResourceAsStream(BOOK_XSD)),
            new StreamSource
                    (this.getClass().getResourceAsStream(BOOK_LIST_XSD)),
        };
        if (!XmlUtils.validateXML(xsdFiles, xmlUrl)) {
            return null;
        }


        try {
            Document doc = getDocument(xmlUrlString);
            Element root = doc.getRootElement();
            List<Element> bookElements = root.getChildren(ROOT_ELEMENT_TAG, root.getNamespace());
            for (Element book : bookElements) {
                books.add(parseBook(book));

            }
        } catch (JDOMException ex) {
            Logger.getLogger(BookXML.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(BookXML.class.getName()).log(Level.SEVERE, null, ex);
        }
        return books;
    }

    /**
     * parse a book
     * @param rootelement of the book node
     * @return Book
     */
    protected static Book parseBook(Element root) {

        // the element has to be validated!!!
        // the order of the elements should then be
        // title
        // author
        // description
        // price
        // link
        // isbn10
        // isbn13


        List<Element> bookElement = root.getChildren();

        String[] bookValues = new String[bookElement.size()];
        int i = 0;
        for (Element element : bookElement) {
            bookValues[i++] = element.getValue();
        }
        return new Book(0,
                bookValues[ISBN10],
                bookValues[ISBN13],
                bookValues[TITLE],
                bookValues[AUTHOR],
                bookValues[DESCRIPTION],
                bookValues[LINK],
                Integer.parseInt(bookValues[PRICE]));
    }

    /**
     * privat help method to get a Document by URL
     * @param url (i.e. http://www.domain.td/helloWorld.xml)
     * @return
     * @throws IOException
     * @throws JDOMException
     */
    private Document getDocument(String url) throws IOException, JDOMException {

        SAXBuilder parser = new SAXBuilder();
        try {
            return parser.build(url);
        } catch (IOException ex) {
            System.out.println(ex.getMessage());
            return null;
        } catch (JDOMException ex) {
            System.out.println(ex.getMessage());
            return null;
        }

    }
}
